"""
系统监控器

提供系统健康状态、资源使用、服务状态等监控功能。
"""

from typing import Dict, List, Optional, Any, Callable
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from enum import Enum
import asyncio
import psutil
import time
import socket
import subprocess
import platform
from pathlib import Path

from .monitor import BaseMonitor, MonitorConfig, MonitorType, MonitorMetrics, MonitorLevel


@dataclass
class SystemMetrics:
    """系统指标"""
    timestamp: datetime = field(default_factory=datetime.now)
    
    # 系统基本信息
    hostname: str = ""
    platform: str = ""
    architecture: str = ""
    python_version: str = ""
    
    # CPU指标
    cpu_count: int = 0
    cpu_usage_percent: float = 0.0
    cpu_freq_current: float = 0.0
    cpu_freq_max: float = 0.0
    load_average: List[float] = field(default_factory=list)
    
    # 内存指标
    memory_total: int = 0
    memory_available: int = 0
    memory_used: int = 0
    memory_percent: float = 0.0
    swap_total: int = 0
    swap_used: int = 0
    swap_percent: float = 0.0
    
    # 磁盘指标
    disk_total: int = 0
    disk_used: int = 0
    disk_free: int = 0
    disk_percent: float = 0.0
    disk_io_read_bytes: int = 0
    disk_io_write_bytes: int = 0
    disk_io_read_count: int = 0
    disk_io_write_count: int = 0
    
    # 网络指标
    network_bytes_sent: int = 0
    network_bytes_recv: int = 0
    network_packets_sent: int = 0
    network_packets_recv: int = 0
    network_connections: int = 0
    
    # 进程指标
    process_count: int = 0
    thread_count: int = 0
    file_descriptor_count: int = 0
    
    # 系统状态
    uptime: float = 0.0
    boot_time: datetime = field(default_factory=datetime.now)
    
    # 自定义指标
    custom_metrics: Dict[str, Any] = field(default_factory=dict)


class ServiceStatus(Enum):
    """服务状态"""
    RUNNING = "running"
    STOPPED = "stopped"
    ERROR = "error"
    UNKNOWN = "unknown"


@dataclass
class ServiceInfo:
    """服务信息"""
    name: str
    status: ServiceStatus
    pid: Optional[int] = None
    cpu_percent: float = 0.0
    memory_percent: float = 0.0
    memory_rss: int = 0
    create_time: Optional[datetime] = None
    last_check: datetime = field(default_factory=datetime.now)
    error_message: str = ""


class SystemResourceMonitor(BaseMonitor):
    """系统资源监控器"""
    
    def __init__(self, config: Optional[MonitorConfig] = None):
        """初始化系统资源监控器"""
        if config is None:
            config = MonitorConfig(
                monitor_id="system_resource",
                monitor_type=MonitorType.SYSTEM,
                name="系统资源监控",
                description="监控CPU、内存、磁盘、网络等系统资源",
                interval=10.0
            )
        super().__init__(config)
        
        # 历史数据
        self._last_disk_io: Optional[Dict[str, int]] = None
        self._last_network_io: Optional[Dict[str, int]] = None
        self._cpu_history: List[float] = []
        self._memory_history: List[float] = []
    
    async def check(self) -> MonitorMetrics:
        """检查系统资源"""
        try:
            # 获取系统基本信息
            system_info = self._get_system_info()
            
            # 获取CPU信息
            cpu_info = self._get_cpu_info()
            
            # 获取内存信息
            memory_info = self._get_memory_info()
            
            # 获取磁盘信息
            disk_info = self._get_disk_info()
            
            # 获取网络信息
            network_info = self._get_network_info()
            
            # 获取进程信息
            process_info = self._get_process_info()
            
            # 创建系统指标
            sys_metrics = SystemMetrics(
                **system_info,
                **cpu_info,
                **memory_info,
                **disk_info,
                **network_info,
                **process_info
            )
            
            # 更新监控指标
            metrics = MonitorMetrics(self.config.monitor_id)
            metrics.update_metrics({
                'cpu_usage_percent': sys_metrics.cpu_usage_percent,
                'memory_percent': sys_metrics.memory_percent,
                'disk_percent': sys_metrics.disk_percent,
                'network_connections': sys_metrics.network_connections,
                'process_count': sys_metrics.process_count,
                'uptime': sys_metrics.uptime,
                'cpu_avg_5min': sum(self._cpu_history) / len(self._cpu_history) if self._cpu_history else 0,
                'memory_avg_5min': sum(self._memory_history) / len(self._memory_history) if self._memory_history else 0
            })
            
            # 更新历史数据
            self._cpu_history.append(sys_metrics.cpu_usage_percent)
            self._memory_history.append(sys_metrics.memory_percent)
            if len(self._cpu_history) > 30:  # 保留最近30个数据点
                self._cpu_history.pop(0)
            if len(self._memory_history) > 30:
                self._memory_history.pop(0)
            
            # 检查系统资源阈值
            await self._check_resource_thresholds(sys_metrics)
            
            return metrics
            
        except Exception as e:
            self._emit_event(
                "system_resource_check_error",
                MonitorLevel.ERROR,
                f"系统资源检查失败: {e}"
            )
            return MonitorMetrics(self.config.monitor_id)
    
    def _get_system_info(self) -> Dict[str, Any]:
        """获取系统基本信息"""
        return {
            'hostname': socket.gethostname(),
            'platform': platform.platform(),
            'architecture': platform.architecture()[0],
            'python_version': platform.python_version(),
            'uptime': time.time() - psutil.boot_time(),
            'boot_time': datetime.fromtimestamp(psutil.boot_time())
        }
    
    def _get_cpu_info(self) -> Dict[str, Any]:
        """获取CPU信息"""
        cpu_freq = psutil.cpu_freq()
        load_avg = psutil.getloadavg() if hasattr(psutil, 'getloadavg') else [0.0, 0.0, 0.0]
        
        return {
            'cpu_count': psutil.cpu_count(),
            'cpu_usage_percent': psutil.cpu_percent(interval=1),
            'cpu_freq_current': cpu_freq.current if cpu_freq else 0.0,
            'cpu_freq_max': cpu_freq.max if cpu_freq else 0.0,
            'load_average': list(load_avg)
        }
    
    def _get_memory_info(self) -> Dict[str, Any]:
        """获取内存信息"""
        memory = psutil.virtual_memory()
        swap = psutil.swap_memory()
        
        return {
            'memory_total': memory.total,
            'memory_available': memory.available,
            'memory_used': memory.used,
            'memory_percent': memory.percent,
            'swap_total': swap.total,
            'swap_used': swap.used,
            'swap_percent': swap.percent
        }
    
    def _get_disk_info(self) -> Dict[str, Any]:
        """获取磁盘信息"""
        disk_usage = psutil.disk_usage('/')
        disk_io = psutil.disk_io_counters()
        
        # 计算IO速率
        disk_io_read_bytes = disk_io.read_bytes if disk_io else 0
        disk_io_write_bytes = disk_io.write_bytes if disk_io else 0
        disk_io_read_count = disk_io.read_count if disk_io else 0
        disk_io_write_count = disk_io.write_count if disk_io else 0
        
        return {
            'disk_total': disk_usage.total,
            'disk_used': disk_usage.used,
            'disk_free': disk_usage.free,
            'disk_percent': (disk_usage.used / disk_usage.total) * 100,
            'disk_io_read_bytes': disk_io_read_bytes,
            'disk_io_write_bytes': disk_io_write_bytes,
            'disk_io_read_count': disk_io_read_count,
            'disk_io_write_count': disk_io_write_count
        }
    
    def _get_network_info(self) -> Dict[str, Any]:
        """获取网络信息"""
        net_io = psutil.net_io_counters()
        connections = len(psutil.net_connections())
        
        return {
            'network_bytes_sent': net_io.bytes_sent if net_io else 0,
            'network_bytes_recv': net_io.bytes_recv if net_io else 0,
            'network_packets_sent': net_io.packets_sent if net_io else 0,
            'network_packets_recv': net_io.packets_recv if net_io else 0,
            'network_connections': connections
        }
    
    def _get_process_info(self) -> Dict[str, Any]:
        """获取进程信息"""
        processes = list(psutil.process_iter())
        thread_count = sum(p.num_threads() for p in processes if p.is_running())
        
        # 文件描述符数量（仅Linux/Unix）
        fd_count = 0
        try:
            if hasattr(psutil, 'Process'):
                current_process = psutil.Process()
                fd_count = current_process.num_fds() if hasattr(current_process, 'num_fds') else 0
        except:
            pass
        
        return {
            'process_count': len(processes),
            'thread_count': thread_count,
            'file_descriptor_count': fd_count
        }
    
    async def _check_resource_thresholds(self, sys_metrics: SystemMetrics) -> None:
        """检查系统资源阈值"""
        # CPU使用率告警
        cpu_threshold = self.config.thresholds.get('cpu_usage', 80.0)
        if sys_metrics.cpu_usage_percent > cpu_threshold:
            self._emit_event(
                "high_cpu_usage",
                MonitorLevel.WARNING,
                f"CPU使用率过高: {sys_metrics.cpu_usage_percent:.1f}%",
                {"cpu_usage": sys_metrics.cpu_usage_percent, "threshold": cpu_threshold}
            )
        
        # 内存使用率告警
        memory_threshold = self.config.thresholds.get('memory_usage', 85.0)
        if sys_metrics.memory_percent > memory_threshold:
            self._emit_event(
                "high_memory_usage",
                MonitorLevel.WARNING,
                f"内存使用率过高: {sys_metrics.memory_percent:.1f}%",
                {"memory_usage": sys_metrics.memory_percent, "threshold": memory_threshold}
            )
        
        # 磁盘使用率告警
        disk_threshold = self.config.thresholds.get('disk_usage', 90.0)
        if sys_metrics.disk_percent > disk_threshold:
            self._emit_event(
                "high_disk_usage",
                MonitorLevel.WARNING,
                f"磁盘使用率过高: {sys_metrics.disk_percent:.1f}%",
                {"disk_usage": sys_metrics.disk_percent, "threshold": disk_threshold}
            )
        
        # 负载平均值告警（仅Unix系统）
        if sys_metrics.load_average and len(sys_metrics.load_average) > 0:
            load_threshold = self.config.thresholds.get('load_average', sys_metrics.cpu_count * 2)
            if sys_metrics.load_average[0] > load_threshold:
                self._emit_event(
                    "high_load_average",
                    MonitorLevel.WARNING,
                    f"系统负载过高: {sys_metrics.load_average[0]:.2f}",
                    {"load_average": sys_metrics.load_average[0], "threshold": load_threshold}
                )


class ServiceMonitor(BaseMonitor):
    """服务监控器"""
    
    def __init__(self, config: Optional[MonitorConfig] = None):
        """初始化服务监控器"""
        if config is None:
            config = MonitorConfig(
                monitor_id="service_monitor",
                monitor_type=MonitorType.SYSTEM,
                name="服务监控",
                description="监控关键服务的运行状态",
                interval=30.0
            )
        super().__init__(config)
        
        # 监控的服务列表
        self._services: Dict[str, ServiceInfo] = {}
        self._service_configs: Dict[str, Dict[str, Any]] = {}
    
    async def check(self) -> MonitorMetrics:
        """检查服务状态"""
        try:
            # 检查所有配置的服务
            for service_name in self._service_configs:
                await self._check_service(service_name)
            
            # 更新监控指标
            metrics = MonitorMetrics(self.config.monitor_id)
            
            running_services = sum(1 for s in self._services.values() if s.status == ServiceStatus.RUNNING)
            stopped_services = sum(1 for s in self._services.values() if s.status == ServiceStatus.STOPPED)
            error_services = sum(1 for s in self._services.values() if s.status == ServiceStatus.ERROR)
            
            metrics.update_metrics({
                'total_services': len(self._services),
                'running_services': running_services,
                'stopped_services': stopped_services,
                'error_services': error_services,
                'service_availability': running_services / len(self._services) if self._services else 1.0
            })
            
            return metrics
            
        except Exception as e:
            self._emit_event(
                "service_check_error",
                MonitorLevel.ERROR,
                f"服务检查失败: {e}"
            )
            return MonitorMetrics(self.config.monitor_id)
    
    def add_service(self, name: str, **config) -> None:
        """添加要监控的服务"""
        self._service_configs[name] = config
        self._services[name] = ServiceInfo(name=name, status=ServiceStatus.UNKNOWN)
    
    async def _check_service(self, service_name: str) -> None:
        """检查单个服务状态"""
        try:
            config = self._service_configs[service_name]
            service_info = self._services[service_name]
            
            # 根据配置类型检查服务
            if 'process_name' in config:
                await self._check_process_service(service_name, config['process_name'])
            elif 'port' in config:
                await self._check_port_service(service_name, config['port'], config.get('host', 'localhost'))
            elif 'command' in config:
                await self._check_command_service(service_name, config['command'])
            
            service_info.last_check = datetime.now()
            
        except Exception as e:
            service_info = self._services[service_name]
            service_info.status = ServiceStatus.ERROR
            service_info.error_message = str(e)
            service_info.last_check = datetime.now()
            
            self._emit_event(
                "service_check_failed",
                MonitorLevel.ERROR,
                f"服务 {service_name} 检查失败: {e}",
                {"service_name": service_name, "error": str(e)}
            )
    
    async def _check_process_service(self, service_name: str, process_name: str) -> None:
        """通过进程名检查服务"""
        service_info = self._services[service_name]
        
        try:
            # 查找进程
            processes = [p for p in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent', 'memory_info', 'create_time'])
                        if p.info['name'] and process_name.lower() in p.info['name'].lower()]
            
            if processes:
                # 取第一个匹配的进程
                process = processes[0]
                service_info.status = ServiceStatus.RUNNING
                service_info.pid = process.info['pid']
                service_info.cpu_percent = process.info['cpu_percent'] or 0.0
                service_info.memory_percent = process.info['memory_percent'] or 0.0
                service_info.memory_rss = process.info['memory_info'].rss if process.info['memory_info'] else 0
                service_info.create_time = datetime.fromtimestamp(process.info['create_time']) if process.info['create_time'] else None
                service_info.error_message = ""
            else:
                service_info.status = ServiceStatus.STOPPED
                service_info.pid = None
                service_info.cpu_percent = 0.0
                service_info.memory_percent = 0.0
                service_info.memory_rss = 0
                service_info.create_time = None
                service_info.error_message = f"进程 {process_name} 未找到"
                
                self._emit_event(
                    "service_stopped",
                    MonitorLevel.WARNING,
                    f"服务 {service_name} 已停止",
                    {"service_name": service_name, "process_name": process_name}
                )
                
        except Exception as e:
            service_info.status = ServiceStatus.ERROR
            service_info.error_message = str(e)
    
    async def _check_port_service(self, service_name: str, port: int, host: str = 'localhost') -> None:
        """通过端口检查服务"""
        service_info = self._services[service_name]
        
        try:
            # 尝试连接端口
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)  # 5秒超时
            result = sock.connect_ex((host, port))
            sock.close()
            
            if result == 0:
                service_info.status = ServiceStatus.RUNNING
                service_info.error_message = ""
            else:
                service_info.status = ServiceStatus.STOPPED
                service_info.error_message = f"端口 {host}:{port} 无法连接"
                
                self._emit_event(
                    "service_port_unreachable",
                    MonitorLevel.WARNING,
                    f"服务 {service_name} 端口不可达: {host}:{port}",
                    {"service_name": service_name, "host": host, "port": port}
                )
                
        except Exception as e:
            service_info.status = ServiceStatus.ERROR
            service_info.error_message = str(e)
    
    async def _check_command_service(self, service_name: str, command: str) -> None:
        """通过命令检查服务"""
        service_info = self._services[service_name]
        
        try:
            # 执行检查命令
            result = subprocess.run(
                command,
                shell=True,
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode == 0:
                service_info.status = ServiceStatus.RUNNING
                service_info.error_message = ""
            else:
                service_info.status = ServiceStatus.STOPPED
                service_info.error_message = f"命令执行失败: {result.stderr}"
                
                self._emit_event(
                    "service_command_failed",
                    MonitorLevel.WARNING,
                    f"服务 {service_name} 检查命令失败",
                    {"service_name": service_name, "command": command, "error": result.stderr}
                )
                
        except subprocess.TimeoutExpired:
            service_info.status = ServiceStatus.ERROR
            service_info.error_message = "命令执行超时"
        except Exception as e:
            service_info.status = ServiceStatus.ERROR
            service_info.error_message = str(e)


class SystemMonitor:
    """
    系统监控器管理器
    
    管理和协调各种系统监控器。
    """
    
    def __init__(self):
        """初始化系统监控器管理器"""
        self.resource_monitor = SystemResourceMonitor()
        self.service_monitor = ServiceMonitor()
        
        self._monitors = {
            'resource': self.resource_monitor,
            'service': self.service_monitor
        }
    
    def start_all(self) -> None:
        """启动所有系统监控器"""
        for monitor in self._monitors.values():
            monitor.start()
    
    def stop_all(self) -> None:
        """停止所有系统监控器"""
        for monitor in self._monitors.values():
            monitor.stop()
    
    def get_system_summary(self) -> Dict[str, Any]:
        """获取系统摘要"""
        summary = {}
        
        for name, monitor in self._monitors.items():
            summary[name] = {
                'status': monitor.status.value,
                'metrics': monitor.metrics.metrics,
                'last_check': monitor.last_check_time.isoformat() if monitor.last_check_time else None,
                'check_count': monitor.check_count,
                'error_count': monitor.error_count
            }
        
        return summary
    
    def add_service(self, name: str, **config) -> None:
        """添加要监控的服务"""
        self.service_monitor.add_service(name, **config)
    
    def get_service_status(self, service_name: str) -> Optional[ServiceInfo]:
        """获取服务状态"""
        return self.service_monitor._services.get(service_name)
    
    def get_all_services(self) -> Dict[str, ServiceInfo]:
        """获取所有服务状态"""
        return self.service_monitor._services.copy()